<template>
  <div
    v-if="!initializing && compInfo.type"
    style="min-height: 100px"
    :class="['cc-page-comp cc-flex-row cc-grow-height', props.class, getClassName(compInfo.type)]"
  >
    <Tree
      v-if="compInfo.showTree === '1'"
      :options="compInfo"
      @change="treeChange"
    />
    <div class="cc-page-comp-container cc-flex-column cc-grow-width">
      <div class="cc-page-comp-bar" v-if="compInfo.type === '表格'">
        <FormQuery
          ref="formQuery"
          v-bind="queryOptions"
          @change="changeQueryData"
          @buttonClick="formQueryButtonClick"
        />
      </div>
      <component
        ref="compRef"
        :is="getComponent(compInfo.type)"
        :operate="operate"
        :disabled="disabled"
        v-bind="compInfo"
        v-bind:initData="initData"
        v-bind:pkFieldName="pkFieldName"
        v-bind:options="getOptions(compInfo.type)"
        v-bind:defaultQuery="queryOptions.defaultQuery"
        v-bind:dataFieldList="dataFieldList"
        v-bind:inputParam="getInputParam(compInfo.type)"
        v-bind:inputParamList="getInputParamList(compInfo.type)"
        @editChange="editChange"
        @buttonClick="compButtonClick"
        @showDetail="showDetail"
        @selectionChange="selectionChange"
      />
      <slot />
    </div>
  </div>
  <div
    v-else
    v-loading="true"
    element-loading-text="数据加载中..."
    style="min-height: 100px"
  ></div>

  <el-dialog
    v-model="dialogVisible"
    :width="dialogWidth"
    append-to-body
    destroy-on-close
    draggable
    :before-close="closeDialog"
    :close-on-click-modal="false"
    :fullscreen="dialogFullscreen"
    :class="['cc-page-comp-dialog', dialogComponent?.__name === 'page' ? 'no-padding' : '']"
  >
    <template #header>
      <div class="header" @dblclick="dialogFullscreen=!dialogFullscreen">
        <div class="title">{{dialogTitle}}</div>
        <div class="button">
          <cc-icon
            v-if="!dialogFullscreen"
            iconId="018dca8cad1b28075ecd"
            @click="dialogFullscreen=true"
            title="最大化"
          />
          <cc-icon
            v-if="dialogFullscreen"
            iconId="018dca8cad1b9b03c47f"
            @click="dialogFullscreen=false"
            title="缩小"
          />
        </div>
      </div>
    </template>
    <component
      ref="dialogCompRef"
      :is="dialogComponent"
      :disabled="!dialogEdit"
      :operate="operate"
      :dialogMode="true"
      v-bind="dialogOptions"
    />
    <template #footer v-if="dialogFooter">
      <el-button
        v-if="dialogEdit"
        size="default"
        type="info"
        @click="dialogVisible = false"
      >取消</el-button>
      <el-button
        v-if="!dialogEdit"
        size="default"
        type="info"
        @click="dialogVisible = false"
      >关闭</el-button>
      <el-button
        v-for="(button, index) in dialogButtons || []"
        :key="index"
        class="cc-dialog-form-button"
        size="default"
        :style="{
          'color': button.fontColor,
          'background-color': button.backgroundColor,
          'border': '1px solid ' + button.borderColor
        }"
        :loading="button.loading === true"
        @click="dialogButtonClick(button)"
      >{{button.name}}
      </el-button>
      <el-button
        v-if="dialogEdit && dialogButtons.filter(item => item.type !== '打印').length === 0"
        size="default"
        type="primary"
        @click="() => submitDialogForm(null)"
        :loading="dialogLoading"
      >提交</el-button>
    </template>
  </el-dialog>

  <el-dialog
    title="导入"
    v-model="importVisible"
    width="800px"
    :close-on-click-modal="false"
    :fullscreen="importFullscreen"
    class="cc-page-comp-dialog"
    draggable
  >
    <template #header>
      <div class="header" @dblclick="importFullscreen=!importFullscreen">
        <div class="title">导入</div>
        <div class="button">
          <cc-icon
            v-if="!importFullscreen"
            iconId="018dca8cad1b28075ecd"
            @click="importFullscreen=true"
            title="最大化"
          />
          <cc-icon
            v-if="importFullscreen"
            iconId="018dca8cad1b9b03c47f"
            @click="importFullscreen=false"
            title="缩小"
          />
        </div>
      </div>
    </template>
    <el-form
      ref="dataForm"
      label-width="120px"
      label-position="right"
    >
      <el-row style="margin-top: 10px;">
        <el-col :span="12">
          <el-form-item label="文件选择" prop="file">
            <el-upload
              ref="importUpload"
              action=""
              accept=".xls, .xlsx"
              :multiple="true"
              :http-request="handleImportUpload"
              :show-file-list=false
              :before-upload="handleBeforeImportUpload"
            >
              <el-button :loading="importLoading" type="success">Excel数据导入</el-button>
              <el-button v-if="importButton.buttonId" type="primary" @click.stop="downloadTpl">模板下载</el-button>
              <el-button
                v-if="importButton.tplType === '自定义'"
                type="primary"
                @click.stop="customButtonEvent({id: importButton.id, type: '下载模板'})"
              >模板下载</el-button>
              <template #tip><div class="el-upload__tip">只能上传xls/xlsx文件</div></template>
            </el-upload>
          </el-form-item>
        </el-col>
        <el-col class="error-text" v-if="importErrorMsg !== ''" :span="24">
          <div v-html="importErrorMsg"></div>
        </el-col>
      </el-row>
    </el-form>
    <template #footer>
      <el-button
        size="default"
        type="info"
        @click="importVisible = false"
      >关闭</el-button>
    </template>
  </el-dialog>
</template>

<script setup>
import { ref, onMounted, markRaw, inject, nextTick, computed } from 'vue';
import Page from '@/codeless/view/page.vue';
import FlowPage from '@/flow/deal.vue';
import FormQuery from '@/codeless/view/form-query.vue';
import Form from '@/codeless/view/form.vue';
import Table from '@/codeless/view/table.vue';
import TableEdit from '@/codeless/view/table-edit.vue';
import Tree from '@/codeless/view/tree.vue';
import api from "@/http/api";
import { ElMessage, ElMessageBox } from "element-plus";
import tool from "@/utils/tool";
import loading from '@/utils/loading';
import { getPageComp, getPageButton, getDataFieldList } from '@/utils/codeless';
import printJS from 'print-js';
import html2canvas from "html2canvas";

const props = defineProps({
  pageCompId: String,
  operate: {
    type: String,
    default: '',
  },
  initData: {
    type: Object,
    default: () => {}
  },
  inputParam: {
    type: Object,
    default: () => {}
  },
  class: String,
  disabled: {
    type: Boolean,
    default: false
  }
});

const initializing = ref(true);
const compRef = ref({});
const compInfo = ref({});
const pageButtonList = ref([]);
const pkFieldName = ref('');
const dataFieldList = ref([]);
const treeInputParams = ref({});

const formQuery = ref();
const queryOptions = ref({
  defaultQuery: {},
  fieldList: [],
  dataTableId: '',
  advanceQuery: '0',
  buttonWrap: '0',
  buttonList: [],
});
const dialogTitle = ref('');
const dialogWidth = ref('');
const dialogFullscreen = ref(false);
const dialogEdit = ref(false);
const dialogVisible = ref(false);
const dialogLoading = ref(false);
const dialogFooter = ref(true);
const dialogComponent = ref();
const dialogOptions = ref({});
const dialogCompRef = ref();
const dialogButton = ref();
const dialogButtonList = ref();

const importVisible = ref(false);
const importFullscreen = ref(false);
const importLoading = ref(false);
const importButton = ref({});
const importErrorMsg = ref('');
const importUpload = ref();
const importDataList = ref([]);
const currMenuId = inject('menuId', '');
const permitMenuId = inject('permitMenuId', '');

const treeChange = (data) => {
  if (!compInfo.value.filterFieldId) return;

  if (compInfo.value.treeMappingType === '一对多') {
    let dataField = dataFieldList.value.find(item => item.id === compInfo.value.filterFieldId);
    if (!dataField) return;

    let params = {};
    params[compInfo.value.filterFieldId] = data && data.data && data.data[compInfo.value.treeOutputFieldName] || '';
    compRef.value && compRef.value.reloadData(params);

    treeInputParams.value[dataField.fieldName] = data && data.data && data.data[compInfo.value.treeOutputFieldName] || '';
  } else if (compInfo.value.treeMappingType === '多对多') {
    let params = {};
    params[compInfo.value.middleInputFieldId] = data && data.data && data.data[compInfo.value.treeOutputFieldName] || '';
    compRef.value && compRef.value.reloadData(params);

    treeInputParams.value[compInfo.value.middleInputFieldName] = data && data.data && data.data[compInfo.value.treeOutputFieldName] || '';
  }
};

const changeQueryData = (data) => {
  compRef.value && compRef.value.reloadData(data);
};

const formQueryButtonClick = (button) => {
  let dataList = compRef.value.getSelectedData && compRef.value.getSelectedData() || [];
  buttonClick(button, dataList);
};

const dialogButtonClick = (button) => {
  dialogFooter.value = true;
  button.dialogPageId = dialogButton.value.dialogPageId || '';
  customButtonEvent(button, dialogCompRef.value.getData && dialogCompRef.value.getData() || {});
};

const compButtonClick = (button, data) => {
  buttonClick(button, data);
};

const buttonClick = (button, data) => {
  dialogFooter.value = true;
  if (button.buttonId) {
    systemButtonEvent(button, data);
  } else {
    customButtonEvent(button, data);
  }
};

const systemButtonEvent = (button, data) => {
  if (button.name === '新增') {
    dialogTitle.value = '新增';
    dialogEdit.value = true;
    dialogWidth.value = button.dialogWidth ? button.dialogWidth : '600px';
    dialogFullscreen.value = button.dialogFullscreen === '1';
    dialogOptions.value = {
      operate: button.name,
      dataFormId: compInfo.value.dataFormId,
      initData: Object.assign({}, tool.deepClone(data || {})),
      inputParam: Object.assign({}, getInputParam('表单'), treeInputParams.value, props.inputParam)
    };
    dialogComponent.value = markRaw(Form);
    dialogLoading.value = false;
    dialogVisible.value = true;
    dialogButton.value = button;
  } else if (button.name === '批量编辑') {
    if (data && Array.isArray(data) && data.length > 0) {
      dialogTitle.value = '批量编辑';
    } else {
      dialogTitle.value = '批量新增';
    }
    dialogEdit.value = true;
    dialogWidth.value = button.dialogWidth ? button.dialogWidth : '600px';
    dialogFullscreen.value = button.dialogFullscreen === '1';
    dialogOptions.value = {
      operate: button.name,
      dataTableId: compInfo.value.dataTableId,
      fieldList: dataFieldList.value,
      dataList: data || [],
      inputParam: Object.assign({}, props.inputParam || {})
    };
    dialogComponent.value = markRaw(TableEdit);
    dialogLoading.value = false;
    dialogVisible.value = true;
    dialogButton.value = button;
  } else if (button.name === '编辑' || button.name === '复制' || button.name === '明细') {
    let pkField = dataFieldList.value.find(item => item.primaryKey === '1');
    if ((!compInfo.value.dataFormId || !pkField) && button.name === '明细') {
      return;
    }
    if (!pkField) {
      ElMessage.error("数据模型未配置主键字段！");
      return;
    }
    if (!data) {
      ElMessage.error("请先选择要" + button.name + "的数据！");
      return;
    }

    if (Array.isArray(data)) {
      if (data.length === 1) {
        data = data[0];
      } else {
        ElMessage.error("只允许一次" + button.name + "一条数据！");
        return;
      }
    } else if (!data[pkField.fieldName]) {
      ElMessage.error("请先选择要" + button.name + "的数据！");
      return;
    }

    dialogEdit.value = true;
    let initData = tool.deepClone(data);
    if (button.name === '复制') {
      initData[pkField.fieldName] = null;
      let find = dataFieldList.value.find(item => (item.fieldType === '字符' && item.autoCreate === '1') || item.fieldType === '附件');
      if (find) {
        initData[find.fieldName] = null;
      }
    } else if (button.name === '明细') {
      initData[pkField.fieldName] = null;
      dialogEdit.value = false;

      if (!button.dialogWidth) {
        let find = compInfo.value.buttonList.find(item => item.name === '新增' || item.name === '编辑');
        if (find) {
          button.dialogWidth = find.dialogWidth;
        } else {
          button.dialogWidth = '800px';
        }
      }
    }
    dialogTitle.value = button.name;
    dialogWidth.value = button.dialogWidth ? button.dialogWidth : '600px';
    dialogFullscreen.value = button.dialogFullscreen === '1';
    dialogOptions.value = {
      operate: button.name,
      dataFormId: compInfo.value.dataFormId,
      initData: initData || {},
    };
    dialogComponent.value = markRaw(Form);
    dialogLoading.value = false;
    dialogVisible.value = true;
    dialogButton.value = button;
  } else if (button.name === '删除') {
    let pkField = dataFieldList.value.find(item => item.primaryKey === '1');
    if (!pkField) {
      ElMessage.error("数据模型未配置主键字段！");
      return;
    }

    if (!data) {
      ElMessage.error("请先选择要" + button.name + "的数据！");
      return;
    }

    let dataList = [];
    if (Array.isArray(data)) {
      data.forEach(item => {
        let dataItem = {};
        dataItem[pkField.fieldName] = item[pkField.fieldName];
        dataList.push(dataItem);
      });
    } else if (data[pkField.fieldName]) {
      let dataItem = {};
      dataItem[pkField.fieldName] = data[pkField.fieldName];
      dataList.push(dataItem);
    }
    if (dataList.length === 0) {
      ElMessage.error("请先选择要" + button.name + "的数据！");
      return;
    }
    let prompt = compInfo.value.submitPrompt || '请确认是否' + button.name + '？'
    ElMessageBox.confirm(prompt, '提示', {type: 'warning'}).then(() => {
      loading.showLoading();
      let url = '/codeless/'
        + currMenuId.value + '/'
        + button.id + '/'
        + compInfo.value.dataModelId + '/delete';
      api.post(url, {dataList: dataList}).then(res => {
        ElMessage.success(res.message);
        loading.hideLoading();
        refreshCompData();
      }).catch(e => {
        loading.hideLoading();
        console.log('操作失败！', button, e);
      });
    }).catch(() => {});
  } else if (button.name === '导入') {
    importErrorMsg.value =  '';
    importLoading.value = false;
    importVisible.value = true;
    importButton.value = button;
  } else if (button.name === '导出') {
    let data = compRef.value.getQueryData && compRef.value.getQueryData() || [];
    let url = '/codeless/'
      + currMenuId.value + '/'
      + button.id + '/exportXls';
    button.loading = true;
    api.downloadFile(url, data).then((res) => {
      try {
        api.saveFileLocal(res);
      } catch(err) {
        let enc = new TextDecoder('utf-8');
        let error = JSON.parse(enc.decode(new Uint8Array(res)));
        ElMessage.error(error.message);
      } finally {
        button.loading = false;
      }
    }).catch(e => {
      button.loading = false;
      console.log('操作失败！', button, e);
    });
  }
};

const closeDialog = (done) => {
  const viewer = document.getElementsByClassName('el-image-viewer__wrapper')[0];
  if(!viewer) {
    done();
  }

  if (dialogButton.value.endRefresh === '1') {
    refreshCompData();
  }
};

const downloadTpl = () => {
  let url = '/codeless/'
    + currMenuId.value  + '/'
    + importButton.value.id + '/'
    + compInfo.value.dataTableId  + '/downloadTpl';
  api.downloadFile(url).then((res) => {
    try {
      api.saveFileLocal(res);
    } catch(err) {
      let enc = new TextDecoder('utf-8');
      let error = JSON.parse(enc.decode(new Uint8Array(res)));
      ElMessage.error(error.message);
    }
  }).catch(e => {
    console.log('操作失败！', e);
  });
};

const fileCount = ref(0);
const handleImportUpload = (option) => {
  if (fileCount.value === 0) {
    importErrorMsg.value = '';
  }

  fileCount.value++;
  return new Promise((resolve, reject) => {
    importErrorMsg.value = '';
    importLoading.value = true;
    let url = '/codeless/'
      + currMenuId.value  + '/'
      + importButton.value.id  + '/'
      + compInfo.value.dataTableId  + '/importXls';
    api.uploadFile(url, {'file': option.file, dataList: JSON.stringify(importDataList.value)}).then(res => {
      fileCount.value--;
      importLoading.value = false;
      if (res.code === '1') {
        if (fileCount.value === 0 && !importErrorMsg.value) {
          ElMessage.success("导入成功！");
          importVisible.value = false;
          refreshCompData();
        }
      } else {
        importErrorMsg.value += option.file.name + "：<br/>" + res.message.replace(/@@@/g, '<br/>') + '<br/><br/>';
      }

      resolve();
    }).catch(e => {
      fileCount.value--;
      importLoading.value = false;
      importErrorMsg.value += option.file.name + "：" + e.message + '<br/><br/>';
      reject();
    });

    importUpload.value && importUpload.value.clearFiles();
    resolve();
  });
};

const handleBeforeImportUpload = (file) => {
  let isLt10M = file.size / 1024 / 1024 < 10;
  if (!isLt10M) {
    ElMessage.error("上传文件大小不能超过 10MB!");
  }

  return isLt10M;
};

const getButtonDefault = (button) => {
  if (!button.updateList || button.updateList.length <= 0) return {};

  let defaultParam = {};
  button.updateList.forEach(param => {
    const field = dataFieldList.value.find(item => item.id === param.fieldId);
    if (field) {
      defaultParam[field.fieldName] = param.fieldValue;
    }
  });
  return defaultParam;
}

const getButtonParam = (button, data) => {
  const buttonParam = {};
  const pageField = JSON.parse(button.pageFieldJson || '[]');

  if (props.inputParam) {
    pageField.forEach(param => {
      if (param.fieldName && props.inputParam[param.fieldName]) {
        buttonParam[param.pageParamId] = props.inputParam[param.fieldName];
      }
    });
  }

  if (!data || (Array.isArray(data) && data.length === 0)) return buttonParam;

  let dataList;
  if (Array.isArray(data)) {
    dataList = data;
  } else {
    dataList = [data];
  }

  pageField.forEach(param => {
    dataList.forEach(item => {
      if (param.fieldName && item[param.fieldName]) {
        buttonParam[param.pageParamId] = (buttonParam[param.pageParamId] ? (buttonParam[param.pageParamId] + ',') : '') + item[param.fieldName];
        buttonParam[param.pageParamName] = (buttonParam[param.pageParamName] ? (buttonParam[param.pageParamName] + ',') : '') + item[param.fieldName];
      } else if (!param.fieldName && param.fieldId) {
        buttonParam[param.pageParamId] = (buttonParam[param.pageParamId] ? (buttonParam[param.pageParamId] + ',') : '') + param.fieldId;
        buttonParam[param.pageParamName] = (buttonParam[param.pageParamName] ? (buttonParam[param.pageParamName] + ',') : '') + param.fieldId;
      }
    });
  });

  return buttonParam;
}

const customButtonEvent = async(button, data) => {
  if (button.dataVolume === '单条') {
    if (Array.isArray(data)) {
      if (data.length !== 1) {
        ElMessage.error("请选择一条记录！");
        return;
      }
      data = data[0];
    }
  } else if (button.dataVolume === '多条'
      && ((Array.isArray(data) && data.length === 0)
        || (!Array.isArray(data) && Object.keys(data).length === 0))) {
    ElMessage.error("请选择操作记录！");
    return;
  }
  if (button.dataVolume === '多条' && !Array.isArray(data)) {
    data = [data];
  }
  if (button.type === '新增' || button.type === '编辑') {
    dialogTitle.value = button.name;
    dialogEdit.value = true;
    dialogWidth.value = button.dialogWidth ? button.dialogWidth : '600px';
    dialogFullscreen.value = button.dialogFullscreen === '1';
    if (button.dialogFormId) {
      dialogOptions.value = {
        operate: button.type,
        dataFormId: button.dialogFormId,
        initData: Object.assign({}, tool.deepClone(data || {})),
        inputParam: Object.assign({},
          button.type === '新增' ? getInputParam('表单') : {},
          button.type === '新增' ? getButtonDefault(button) : {},
          getButtonParam(button, data),
          treeInputParams.value,
          props.inputParam || {}
        )
      };
      dialogComponent.value = markRaw(Form);
    } else if (button.dialogPageId) {
      dialogOptions.value = {
        operate: button.type,
        dataPageId: button.dialogPageId,
        initData: Object.assign({}, tool.deepClone(data || {})),
        inputParam: Object.assign({},
          button.type === '新增' ? getInputParam('表单') : {},
          button.type === '新增' ? getButtonDefault(button) : {},
          getButtonParam(button, data),
          treeInputParams.value,
          props.inputParam || {}
        )
      };
      dialogComponent.value = markRaw(Page);
    }
    dialogLoading.value = false;
    dialogVisible.value = true;
    dialogButton.value = button;
  } else if (button.type === '删除') {
    if (button.submitPrompt) {
      let result = await ElMessageBox.confirm(button.submitPrompt, {type: 'warning'}).catch(() => {});
      if (!result) return;
    }

    if (!button.executeScriptId) {
      let pkField = dataFieldList.value.find(item => item.primaryKey === '1');
      if (!pkField) {
        ElMessage.error("数据模型未配置主键字段！");
        return;
      }

      let dataList = [];
      if (Array.isArray(data)) {
        data.forEach(item => {
          let dataItem = {};
          dataItem[pkField.fieldName] = item[pkField.fieldName];
          dataList.push(dataItem);
        });
      } else if (data[pkField.fieldName]) {
        let dataItem = {};
        dataItem[pkField.fieldName] = data[pkField.fieldName];
        dataList.push(dataItem);
      }
      if (dataList.length === 0) {
        ElMessage.error("请先选择要" + button.name + "的数据！");
        return;
      }
      loading.showLoading();
      let url = '/codeless/'
        + currMenuId.value + '/'
        + button.id + '/'
        + compInfo.value.dataModelId + '/delete';
      api.post(url, {dataList: dataList}).then(res => {
        ElMessage.success(res.message);
        loading.hideLoading();
        refreshCompData();
      });
    } else {
      let dataList;
      if (Array.isArray(data)) {
        dataList = data;
      } else if (Object.keys(data).length > 0) {
        dataList = [data];
      } else {
        dataList = [];
      }
      api.runScript(button.executeScriptId, {dataList: dataList}).then(res => {
        refreshCompData();
        if (button.showExecuteResult === '1' && (res.data || res.message)) {
          ElMessage.success(res.data || res.message);
        } else {
          ElMessage.success(button.name + "成功！");
        }
      });
    }
  } else if (button.type === '提交数据') {
    dialogButton.value = button;
    submitDialogForm(data);
  } else if (button.type === '批量编辑') {
    dialogTitle.value = button.name;
    dialogEdit.value = true;
    dialogWidth.value = button.dialogWidth ? button.dialogWidth : '600px';
    dialogFullscreen.value = button.dialogFullscreen === '1';

    if (button.dialogFormId) {
      dialogOptions.value = {
        operate: button.type,
        batchEdit: "1",
        dataFormId: button.dialogFormId,
        dataList: tool.deepClone(data || []),
        defaultValue: Object.assign({},
          getButtonDefault(button),
          getButtonParam(button, data),
          treeInputParams.value
        ),
        inputParam: props.inputParam || {}
      };
      dialogComponent.value = markRaw(Form);
    } else if (button.dialogPageId) {
      dialogOptions.value = {
        operate: button.type,
        dataPageId: button.dialogPageId,
        initData: Object.assign({}, tool.deepClone(data || {})),
        defaultValue: getButtonDefault(button),
        inputParam: Object.assign({},
          getButtonParam(button, data),
          treeInputParams.value,
          props.inputParam || {}
        )
      };
      dialogComponent.value = markRaw(Page);
    }

    dialogLoading.value = false;
    dialogVisible.value = true;
    dialogButton.value = button;
  } else if (button.type === '弹出页面') {
    if (!button.dialogPageId) {
      ElMessage.error('按钮【' + button.name + '】未配置弹窗页面！');
      return;
    }

    dialogFooter.value = button.showCloseButton === '1';
    dialogTitle.value = button.name;
    dialogEdit.value = false;
    dialogWidth.value = button.dialogWidth ? button.dialogWidth : '600px';
    dialogFullscreen.value = button.dialogFullscreen === '1';
    dialogOptions.value = {
      dataPageId: button.dialogPageId,
      initData: Object.assign({}, tool.deepClone(data || {})),
      inputParam: Object.assign({}, getButtonParam(button, data), treeInputParams.value),
      disabled: true,
    };
    dialogComponent.value = markRaw(Page);
    dialogLoading.value = false;
    dialogVisible.value = true;
    dialogButton.value = button;
  } else if (button.type === '调用脚本') {
    if (!button.executeScriptId) {
      ElMessage.error('按钮【' + button.name + '】未配置提交执行脚本！');
      return;
    }

    if (button.buttonId || button.submitValidate === '1') {
      dialogCompRef.value.validate(valid => {
        if (valid) {
          doRunScript(button, data);
        }
      }).catch(() => {
        ElMessage.error("数据录入不正确，请重新检查！");
      });
    } else {
      await doRunScript(button, data);
    }
  } else if (button.type === '上传') {
    importErrorMsg.value = '';
    importLoading.value = false;
    importVisible.value = true;

    if (Array.isArray(data)) {
      importDataList.value = data;
    } else if (Object.keys(data).length > 0) {
      importDataList.value = [data];
    } else {
      importDataList.value = [];
    }

    importButton.value = button;
  } else if (button.type === '下载') {
    let data = tool.deepClone(compRef.value.getQueryData && compRef.value.getQueryData() || {});
    let url = '/codeless/'
      + currMenuId.value + '/'
      + button.id + '/exportXls';
    button.loading = true;
    api.downloadFile(url, data).then((res) => {
      try {
        api.saveFileLocal(res);
      } catch(err) {
        let enc = new TextDecoder('utf-8');
        let error = JSON.parse(enc.decode(new Uint8Array(res)));
        ElMessage.error(error.message);
      } finally {
        button.loading = false;
      }
    }).catch(e => {
      button.loading = false;
      console.log('操作失败！', button, e);
    });
  } else if (button.type === '下载模板') {
    let url = '/codeless/'
      + currMenuId.value  + '/'
      + button.id + '/downloadTpl';
    button.loading = true;
    api.downloadFile(url).then((res) => {
      try {
        api.saveFileLocal(res);
      } catch(err) {
        let enc = new TextDecoder('utf-8');
        let error = JSON.parse(enc.decode(new Uint8Array(res)));
        ElMessage.error(error.message);
      } finally {
        button.loading = false;
      }
    }).catch(e => {
      console.log('操作失败！', e);
      button.loading = false;
    });
  } else if (button.type === '打印') {
    buttonPrint();
  }
};

const buttonPrint = () => {
  if (!dialogCompRef.value) {
    ElMessage.error("未知错误！");
  }

  let printNode = dialogCompRef.value.$el.querySelector(".vc-print-node");
  if (!printNode) {
    printNode = dialogCompRef.value.$el;
  }
  printNode.id = tool.uuid();
  printNode.style.transform = 'scale(2)';
  html2canvas(printNode, {
    imageSmoothingEnabled: false
  }).then(canvas => {
    const url = canvas.toDataURL();
    printJS({
      printable: url,
      type: 'image'
    });
  });
  printNode.id = '';
  printNode.style.transform = '';
}

const showDetail = (data) => {
  let button = compInfo.value.buttonList.find(item => item.name === '明细');
  systemButtonEvent(button || {name: '明细'}, data)
};

const selectionChange = (dataList) => {
  formQuery.value.validateButtons(dataList, dataFieldList.value);
};

const loadCompInfo = async(id) => {
  let pageComp = await getPageComp(id, permitMenuId.value);
  let data = pageComp || {};
  data.pageCompId = data.id || '';
  compInfo.value = data;
};

const loadDataField = async() => {
  dataFieldList.value = await getDataFieldList(compInfo.value.dataModelId);
  let pkField = dataFieldList.value.find(item => item.primaryKey === '1');
  if (pkField) {
    pkFieldName.value = pkField.fieldName;
  }
};

const loadPageButton = async() => {
  pageButtonList.value = await getPageButton();
};

const className = ref({'表格': 'cc-page-table', '表单': 'cc-page-form', '页面': 'cc-page-page'});
const getClassName = (key) => {
  return className.value[key] || '';
};

const getComponent = (type) => {
  switch (type) {
    case '表格':
      return Table;
    case '表单':
      return Form;
    case '页面':
      return Page;
    case '流程页面':
      return FlowPage;
    default:
      return '';
  }
};

const getOptions = (type) => {
  switch (type) {
    case '表格':
      return {};
    case '表单':
      return {
        pageCompId: compInfo.value.id || '',
        dataModelId: compInfo.value.dataModelId || '',
        loading: true,
        disabled: props.edit || false
      };
    case '页面':
      return {};
    case '流程页面':
      return getInputParam('页面');
    default:
      return {};
  }
};

const getInputParam = (type) => {
  const inputParam = {};
  (compInfo.value.paramList || [])
    .filter(param => !param.useType || param.useType === '全部' || param.useType === type)
    .forEach(param => {
      if ((props.inputParam || {})[param.pageParamId]) {
        inputParam[param.pageCompParamId] = props.inputParam[param.pageParamId];
      }
    });
  return inputParam;
};

const getInputParamList = (type) => {
  const inputParamList = [];
  (compInfo.value.paramList || [])
    .filter(param => !param.useType || param.useType === '全部' || param.useType === type)
    .forEach(param => {
      if ((props.inputParam || {})[param.pageParamId]) {
        inputParamList.push([param.pageCompParamId, param.matchMode, props.inputParam[param.pageParamId]]);
      }
    });
  return inputParamList;
};

const typeCompNameMap = ref({
  '输入框': 'cc-input',
  '下拉框': 'cc-select',
  '单选框': 'cc-radio',
  '按钮组': 'cc-buttons',
  '日期控件': 'cc-date',
  '树形控件': 'cc-tree'
});
const initQueryOptions = async() => {
  let fieldList = [];
  for (const filter of compInfo.value.filterList) {
    let result = {
      id: filter.id,
      type: typeCompNameMap.value[filter.type] || '',
      placeholder: filter.placeholder,
      defaultValue: filter.defaultValue || '',
    };
    if (filter.type === '输入框') {
      let field = dataFieldList.value.find(field => field.id === filter.fieldIds);

      if (field && field.fieldType === '整数') {
        result.type = 'cc-number';
        result.point = 0;
        result.defaultValue = filter.defaultValue ? parseInt(filter.defaultValue) : null;
      } else if (field && field.fieldType === '小数') {
        result.type = 'cc-number';
        result.point = field.fieldPrecision || 2;
        result.defaultValue = filter.defaultValue ? parseFloat(filter.defaultValue) : null;
      }
    } else if ('下拉框,单选框,按钮组'.indexOf(filter.type) >= 0) {
      let field = dataFieldList.value.find(field => field.id === filter.fieldIds);
      if (!field) return;

      if (field.fieldType === "派生") {
        const res = await api.post('/business/data-field/' + field.sourceFieldId);
        field = res.data || {};
      }

      if (field.fieldType === "联动" && field.relevanceType?.startsWith("字典")) {
        if (filter.type === '下拉框') {
          result.type = 'cc-dict-select';
          if (filter.queryType === '包含') {
            result.multiple = true;
          }
        } else if (filter.type === '单选框') {
          result.type = 'cc-dict-radio';
        } else {
          result.type = 'cc-dict-buttons';
        }
        result.dictCode = field.relevanceDict;
      } else if (field.fieldType === "联动") {
        let dataField = dataFieldList.value.find(field => field.id === filter.fieldIds);
        if (!dataField) return;

        let relevanceList = dataField.relevanceList || [];
        result.relevanceList = relevanceList || [];
        result.type = relevanceList.length === 1 ? 'cc-remote-select' : '';
        result.dataModelId = relevanceList[0].dataModelId;
        result.idProp = relevanceList[0].nodeFieldId;
        result.nameProp = relevanceList[0].showFieldId;
        result.filterName = relevanceList[0].showFieldName;
        result.sortField = relevanceList[0].ordinalFieldId;
      } else {
        result.options = field.enumerateValue || '';
        result.type = field.enumerateValue ? result.type : '';
      }
      if (!result.type && filter.type === '下拉框' && (field.fieldType === '字符' || field.fieldType === '整数')) {
        result.dataModelId = compInfo.value.dataModelId || '';
        result.distinctName = field.fieldName;
        result.filterName = field.fieldName;
        result.type = 'cc-remote-distinct';
        if (filter.queryType === '包含') {
          result.multiple = true;
        }
      }
    } else if (filter.type === '树形控件') {
      let field = dataFieldList.value.find(field => field.id === filter.fieldIds);
      if (!field) return;

      if (field.fieldType === "派生") {
        const res = await api.post('/business/data-field/' + field.sourceFieldId);
        field = res.data || {};
      }

      if (field.relevanceType === '区划树') {
        result.type = 'cc-region-tree';
      } else if (field.relevanceType === '单位树') {
        result.type = 'cc-unit-tree';
      } else if (field.relevanceType === '企业树') {
        result.type = 'cc-entp-tree';
      } else if (field.relevanceType === '部门树') {
        result.type = 'cc-organization-tree';
      } else if (field.relevanceType === '人员树') {
        result.type = 'cc-employee-tree';
        result.withOrgId = false;
      } else {
        let relevanceList = field.relevanceList || [];
        result.relevanceList = relevanceList || [];
        result.type = relevanceList.length > 0 ? result.type : '';
        result.dataFieldId = field.id;
      }
    }

    if (result.type) {
      fieldList.push(result);
    }
  }

  (compInfo.value.buttonList || []).forEach(button => {
    if (button.buttonId) {
      let find = pageButtonList.value.find(item => item.id === button.buttonId);
      if (find) {
        button.name = find.showName;
        button.dataVolume = find.dataVolume;
        button.showPosition = button.showPosition || find.showPosition;
        button.iconId = find.iconId;
        button.fontColor = find.fontColor;
        button.backgroundColor = find.backgroundColor;
        button.borderColor = find.borderColor;
        button.submitPrompt = find.submitPrompt;
      }
    }
  });

  queryOptions.value = {
    dataTableId: compInfo.value.dataTableId || '',
    advanceQuery: compInfo.value.advanceQuery || '0',
    buttonWrap: compInfo.value.buttonWrap || '0',
    fieldList: fieldList,
    defaultQuery: fieldList.reduce((obj, item) => ({...obj, [item.id]: item.defaultValue}), {}),
    buttonList: (compInfo.value.buttonList || []).filter(item => item.showPosition.indexOf('顶部') >= 0)
  };
};

const submitDialogForm = (data) => {
  if (dialogButton.value.buttonId || dialogButton.value.submitValidate === '1') {
    dialogCompRef.value.validate(valid => {
      if (valid) {
        doSubmitDialogForm(data);
      }
    }).catch(() => {
      ElMessage.error("数据录入不正确，请重新检查！");
    });
  } else {
    doSubmitDialogForm(data);
  }
};

const doSubmitDialogForm = (data) => {
  let prompt = dialogButton.value.submitPrompt || "请确认是否提交数据？";
  ElMessageBox.confirm(prompt, '提示', {type: 'info'}).then(() => {
    let url = '';
    if (dialogButton.value.buttonId) {
      if (dialogButton.value.name === '批量编辑') {
        url = '/codeless/'
          + currMenuId.value + '/'
          + dialogButton.value.id + '/'
          + compInfo.value.dataTableId + '/saveTableList';
      } else {
        url = '/codeless/'
          + currMenuId.value + '/'
          + dialogButton.value.id + '/'
          + compInfo.value.dataModelId + '/saveModel';
      }
    } else if (dialogButton.value.type === '提交数据') {
      if (Array.isArray(data)) {
        url = '/codeless/'
          + currMenuId.value + '/'
          + dialogButton.value.id + '/'
          + compInfo.value.dataModelId + '/saveModelList';
      } else {
        if (dialogButton.value.dialogPageId) {
          url = '/codeless/'
            + currMenuId.value + '/'
            + dialogButton.value.id + '/'
            + dialogButton.value.dialogPageId + '/savePage';
        } else {
          url = '/codeless/'
            + currMenuId.value + '/'
            + dialogButton.value.id + '/'
            + compInfo.value.dataModelId + '/saveModel';
        }
      }
    } else {
      if (dialogButton.value.type === '新增'
          || dialogButton.value.type === '编辑'
          || dialogButton.value.type === '批量编辑') {
        if (dialogButton.value.saveAndRun === '1') {
          url = '/codeless/' + currMenuId.value + '/' + dialogButton.value.id + '/';
          if (dialogButton.value.type === '批量编辑') {
            url += dialogButton.value.dialogFormId + '/saveFormList';
          } else if (dialogButton.value.dialogFormId) {
            url += dialogButton.value.dialogFormId + '/saveForm';
          } else if (dialogButton.value.dialogPageId) {
            url += dialogButton.value.dialogPageId + '/savePage';
          }
        } else if (dialogButton.value.executeScriptId) {
          url = '/codeless/script/'
            + currMenuId.value + '/'
            + dialogButton.value.id + '/'
            + dialogButton.value.executeScriptId + '/run';
        } else if (dialogButton.value.dialogFormId) {
          url = '/codeless/' + currMenuId.value + '/' + dialogButton.value.id + '/';
          if (dialogButton.value.type === '批量编辑') {
            url += dialogButton.value.dialogFormId + '/saveFormList';
          } else if (dialogButton.value.dialogFormId) {
            url += dialogButton.value.dialogFormId + '/saveForm';
          }
        } else if (dialogButton.value.dialogPageId) {
          url = '/codeless/'
            + currMenuId.value + '/'
            + dialogButton.value.id + '/'
            + dialogButton.value.dialogPageId + '/savePage';
        } else {
          ElMessage.error('按钮【' + dialogButton.value.name + '】未配置弹窗表单！');
          return;
        }
      }
    }

    dialogLoading.value = true;
    api.post(url, data || dialogCompRef.value.getData()).then(res => {
      ElMessage.success(res.message);
      dialogLoading.value = false;
      dialogVisible.value = false;
      refreshCompData();
    }).catch(e => {
      dialogLoading.value = false;
      console.log('操作失败！', e);
    });
  }).catch(() => {});
};

const doRunScript = async(button, data) => {
  if (button.submitPrompt) {
    let result = await ElMessageBox.confirm(button.submitPrompt, {type: 'warning'}).catch(() => {});
    if (!result) return;
  }

  let param;
  if (Array.isArray(data)) {
    param = {dataList: data};
  } else if (Object.keys(data).length > 0) {
    param = data;
  } else {
    param = [];
  }
  button.loading = true;
  api.runScript(button.executeScriptId, param).then(res => {
    if (button.endRefresh === '1') {
      refreshCompData();
    }
    if (button.showExecuteResult === '1' && (res.data || res.message)) {
      ElMessage.success(res.data || res.message);
    } else {
      ElMessage.success(button.name + "成功！");
    }
    dialogLoading.value = false;
    dialogVisible.value = false;
    button.loading = false;
  }).catch(e => {
    console.log(e)
    button.loading = false;
    dialogLoading.value = false;
  });
};

const refreshCompData = () => {
  compRef.value && compRef.value.refreshData && compRef.value.refreshData();
};

const editChange = (data) => {
  let url = '/codeless/'
    + currMenuId.value + '/'
    + compInfo.value.dataModelId + '/saveModel';
  api.post(url, data).then(res => {
    ElMessage.success(res.message);
    dialogLoading.value = false;
    dialogVisible.value = false;
    // refreshCompData();
  }).catch(e => {
    dialogLoading.value = false;
    console.log('操作失败！', e);
  });
};

const initDialogButton = async() => {
  dialogButtonList.value = (compInfo.value.buttonList || []).filter(item => item.showPosition.indexOf('表单') >= 0)
};

const init = async() => {
  if (!props.pageCompId) {
    return;
  }

  initializing.value = true;
  await loadCompInfo(props.pageCompId);
  await loadDataField();
  await loadPageButton();
  await initQueryOptions();
  await initDialogButton();
  await nextTick(() => initializing.value = false);
};

const validate = (callback) => {
  const promise = new Promise((resolve, reject) => {
    compRef.value && compRef.value
      .validate(valid => resolve(valid))
      .catch(e => {
        console.log('组件校验异常！', e);
        reject(e);
      });
  });
  promise
    .then(valid => callback(valid))
    .catch(e => {
      console.log('组件校验异常！', e);
      callback(false);
    });
  return promise;
};

const getData = () => {
  return compRef.value && compRef.value.getData && compRef.value.getData() || {};
};

const dialogButtons = computed(() => {
  if (dialogButton.value.name === '批量编辑' || dialogButtonList.value.length === 0) return [];
  return dialogButtonList.value.filter(item => !item.bindButton || item.bindButton === dialogButton.value.name);
});

onMounted(() => {
  init();
});

defineExpose({ validate, getData, refreshCompData });
</script>

<style scoped>
.cc-dialog-form-button:hover {
  filter: opacity(0.7);
}
.cc-dialog-form-button:focus-visible {
  outline: unset;
}
.cc-dialog-form-button:active {
  filter: brightness(90%);
}
</style>